package com.base.xm.fingerprintdemo.utils;

import android.Manifest;
import android.app.KeyguardManager;
import android.content.Context;
import android.content.pm.PackageManager;
import android.hardware.fingerprint.FingerprintManager;
import android.os.Build;
import android.os.CancellationSignal;
import android.security.keystore.KeyProperties;
import android.support.annotation.RequiresApi;
import android.support.v4.app.ActivityCompat;
import android.util.Base64;
import android.util.Log;

import javax.crypto.Cipher;

/**
 * 指纹识别工具类
 */
@RequiresApi(api = Build.VERSION_CODES.M)
public class FingerprintHelper extends FingerprintManager.AuthenticationCallback {
    private static FingerprintManager manager;
    private CancellationSignal cancellationSignal;
    private Callback callback;
    private static LocalSharedPreference localSharedPreference;
    private static LocalAndroidKeyStore localAndroidKeyStore;
    private int purpose = KeyProperties.PURPOSE_DECRYPT;
    private String data;
    private static Context context;

    private static FingerprintHelper helper;

    public static FingerprintHelper getIntance(Context c) {
        context = c;
        if (helper == null) {
            helper = new FingerprintHelper();
            manager = context.getSystemService(FingerprintManager.class);
            localSharedPreference = new LocalSharedPreference(context);
            localAndroidKeyStore = new LocalAndroidKeyStore();
        }
        return helper;
    }

    /**
     * 判断手机硬件是否支持指纹识别
     *
     * @return
     */
    private boolean isHardwareDetected() {
        return manager.isHardwareDetected();
    }

    /**
     * 检查是否有权限
     *
     * @return
     */
    private boolean hasPermission() {
        return ActivityCompat.checkSelfPermission(context, Manifest.permission.USE_FINGERPRINT) ==
                PackageManager.PERMISSION_GRANTED;

    }

    /**
     * 判断手机是否至少录入了一个指纹
     *
     * @return
     */
    private boolean hasEnrolledFingerprints() {
        return manager.hasEnrolledFingerprints();
    }

    /**
     * 判断手机是否设置了锁屏
     *
     * @return
     */
    private boolean isKeyguardSecure() {
        KeyguardManager keyguardManager = (KeyguardManager) context
                .getSystemService(Context.KEYGUARD_SERVICE);
        return keyguardManager.isKeyguardSecure();
    }

    /**
     * 设置回调监听
     *
     * @param callback
     */
    public void setCallback(Callback callback) {
        this.callback = callback;
    }

    /**
     * 设置验证目的
     *
     * @param purpose
     */
    public void setPurpose(int purpose) {
        this.purpose = purpose;
    }

    /**
     * 设置要加密的数据
     *
     * @param data
     */
    public void setEncodeValue(String data) {
        this.data = data;
    }

    /**
     * 获取要加密的数据
     *
     * @return
     */
    public String getEncodeValue() {
        return data;
    }

    /**
     * 验证指纹
     */
    public void authenticate() {
        if (!isHardwareDetected() && callback != null)
            callback.onHardwareNotSupported();

        if (!hasPermission() && callback != null)
            callback.onNoPermission();

        if (!isKeyguardSecure() && callback != null)
            callback.onKeyguardSecure();

        if (!hasEnrolledFingerprints() && callback != null)
            callback.onNotEnrolledFingerprints();

        try {
            FingerprintManager.CryptoObject object = null;
            if (purpose == KeyProperties.PURPOSE_DECRYPT) {//解密
                String IV = localSharedPreference.getString(LocalSharedPreference.IV_NAME);
                object = localAndroidKeyStore.getCryptoObject(purpose, Base64.decode(IV, Base64.URL_SAFE));
            } else if (purpose == KeyProperties.PURPOSE_ENCRYPT) {//加密
                object = localAndroidKeyStore.getCryptoObject(purpose, null);
            }
            cancellationSignal = new CancellationSignal();
            manager.authenticate(object, cancellationSignal, 0, this, null);
        } catch (SecurityException e) {
            e.printStackTrace();
        }
    }

    /**
     * 停止验证
     */
    public void stopAuthenticate() {
        if (cancellationSignal != null) {
            cancellationSignal.cancel();
            cancellationSignal = null;
        }
        callback = null;
    }

    /**
     * 指纹验证成功的回调
     *
     * @param result
     */
    @Override
    public void onAuthenticationSucceeded(FingerprintManager.AuthenticationResult result) {
        try {
            Cipher cipher = result.getCryptoObject().getCipher();
            if (purpose == KeyProperties.PURPOSE_DECRYPT) {//解密
                String data = localSharedPreference.getString(LocalSharedPreference.DATA_NAME);
//                byte[] decrypted = cipher.doFinal(Base64.decode(data, Base64.URL_SAFE));
//                callback.onAuthenticationSucceeded(new String(decrypted));
                callback.onAuthenticationSucceeded((String) cipher.getProvider().get(LocalSharedPreference.TOKEN));
            } else if (purpose == KeyProperties.PURPOSE_ENCRYPT) {//加密
                cipher.getProvider().setProperty(LocalSharedPreference.TOKEN, getEncodeValue());

                byte[] encrypted = cipher.doFinal(getEncodeValue().getBytes());
                byte[] IV = cipher.getIV();
                String se = Base64.encodeToString(encrypted, Base64.URL_SAFE);
                String siv = Base64.encodeToString(IV, Base64.URL_SAFE);
                localSharedPreference.putString(LocalSharedPreference.DATA_NAME, se);
                localSharedPreference.putString(localSharedPreference.IV_NAME, siv);
//                callback.onAuthenticationSucceeded(se);
                callback.onAuthenticationSucceeded(getEncodeValue());
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 指纹验证失败的回调：验证失败已超过5次，不可再验
     *
     * @param errorCode
     * @param errString
     */
    @Override
    public void onAuthenticationError(int errorCode, CharSequence errString) {
        if (callback != null)
            callback.onAuthenticationError(errorCode, errString);
    }

    /**
     * 指纹验证失败的回调：可再验，可能手指过脏，或者移动过快等原因
     *
     * @param helpCode
     * @param helpString
     */
    @Override
    public void onAuthenticationHelp(int helpCode, CharSequence helpString) {
        if (callback != null)
            callback.onAuthenticationHelp(helpCode, helpString);
    }

    /**
     * 指纹验证失败的回调：指纹识别失败，可再验，该指纹不是系统录入的指纹
     */
    @Override
    public void onAuthenticationFailed() {
        if (callback != null)
            callback.onAuthenticationFailed();
    }

    public interface Callback {
        //硬件不支持指纹识别
        void onHardwareNotSupported();

        //没有权限
        void onNoPermission();

        //手机没有录入指纹
        void onNotEnrolledFingerprints();

        //手机已设置锁屏
        void onKeyguardSecure();

        //指纹识别成功
        void onAuthenticationSucceeded(String value);

        //指纹识别失败超过5次
        void onAuthenticationError(int errorCode, CharSequence errString);

        //指纹识别失败可再验证
        void onAuthenticationHelp(int helpCode, CharSequence helpString);

        //指纹识别失败
        void onAuthenticationFailed();
    }
}
